﻿using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Linq;
using System.Text;
using System.Collections;

using WorkStation.Frameworks.Core.Json;

namespace WorkStation.Frameworks.Core.Extensions
{
    /// <summary>
    /// IEnumerable接口的静态扩展类
    /// </summary>
    public static class IEnumerableExtensions
    {
        /// <summary>
        /// * 转换集合为JSON数据
        /// </summary>
        /// <param name="value">被转换集合</param>
        /// <returns></returns>
        public static string ToJson(this IEnumerable value)
        {
            return JsonHelper.ToJson(value);
        }

        /// <summary>
        /// * 扩展IEnumerable接口，使之具有ForEach功能
        /// </summary>
        /// <typeparam name="TItem">数据项</typeparam>
        /// <param name="value">集合</param>
        /// <param name="action">动作</param>
        public static void ForEach<TItem>(this IEnumerable<TItem> value, Action<TItem> action) 
        {
            foreach (var item in value) 
            {
                action.Invoke(item);
            }
        }

        /// <summary>
        /// * 扩展IEnumerable接口，使之具有ForEach功能
        /// </summary>
        /// <typeparam name="TItem">数据项</typeparam>
        /// <param name="value">集合</param>
        /// <param name="action">动作</param>
        public static void ForEach<TItem>(this IEnumerable<TItem> value, Action<TItem, int> action) 
        {
            int index = 0;

            foreach (TItem item in value) 
            {
                action.Invoke(item, index);
                index++;
            }
        }

        /// <summary>
        /// * 并行MapReduce计算
        /// </summary>
        /// <typeparam name="TInput">输入类型</typeparam>
        /// <typeparam name="TKey">Key类型</typeparam>
        /// <typeparam name="TValue">Value类型</typeparam>
        /// <typeparam name="TResult">结果类型</typeparam>
        /// <param name="list">数据源</param>
        /// <param name="map">Map函数</param>
        /// <param name="reduce">Reduce函数</param>
        /// <returns></returns>
        public static Dictionary<TKey, TResult> ParallelMapReduce<TInput, TKey, TValue, TResult>(this IEnumerable<TInput> list, Func<TInput, IEnumerable<KeyValuePair<TKey, TValue>>> map, Func<TKey, IEnumerable<TValue>, TResult> reduce) 
        {
            ConcurrentDictionary<TKey, List<TValue>> mapResult = new ConcurrentDictionary<TKey,List<TValue>>();

            System.Threading.Tasks.Parallel.ForEach(list, item => {

                System.Threading.Tasks.Parallel.ForEach(map(item), res => {
                    List<TValue> mapValues = mapResult.GetOrAdd(res.Key, key =>
                    {
                        return new List<TValue>();
                    });

                    lock (mapValues)
                    {
                        mapValues.Add(res.Value);
                    }
                });
            });

            Dictionary<TKey, TResult> output = new Dictionary<TKey, TResult>();

            System.Threading.Tasks.Parallel.ForEach(mapResult, item => {
                output.Add(item.Key, reduce(item.Key, item.Value));
            });

            return output;
        }

        /// <summary>
        /// * 串行MapReduce计算
        /// </summary>
        /// <typeparam name="TInput">输入类型</typeparam>
        /// <typeparam name="TKey">Key类型</typeparam>
        /// <typeparam name="TValue">Value类型</typeparam>
        /// <typeparam name="TResult">结果类型</typeparam>
        /// <param name="list">数据源</param>
        /// <param name="map">Map函数</param>
        /// <param name="reduce">Reduce函数</param>
        /// <returns></returns>
        public static Dictionary<TKey, TResult> MapReduce<TInput, TKey, TValue, TResult>(this IEnumerable<TInput> list, Func<TInput, IEnumerable<KeyValuePair<TKey, TValue>>> map, Func<TKey, IEnumerable<TValue>, TResult> reduce)
        {
            Dictionary<TKey, List<TValue>> mapResult = new Dictionary<TKey, List<TValue>>();

            list.ForEach(item =>
            {
                map(item).ForEach(res =>
                {
                    List<TValue> mapValues = null;

                    if (!mapResult.TryGetValue(res.Key, out mapValues)) 
                    {
                        mapValues = new List<TValue>();
                        mapResult.Add(res.Key, mapValues);
                    }

                    mapValues.Add(res.Value);
                });
            });

            Dictionary<TKey, TResult> output = new Dictionary<TKey, TResult>();

            mapResult.ForEach(item =>
            {
                output.Add(item.Key, reduce(item.Key, item.Value));
            });

            return output;
        }

        /// <summary>
        /// 扩展IEnumerable接口，随机取一个值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="collection"></param>
        /// <returns></returns>
        public static T FirstByRandom<T>(this IEnumerable<T> collection)
        {
            int seed1 = Guid.NewGuid().GetHashCode();
            int seed2 = unchecked((int)DateTime.Now.Ticks);

            Random dom = new Random(seed1 + seed2);
            
            int max = collection.Count();
            
            int result = dom.Next(0, max);

            return collection.ElementAt(result);
        }

        /// <summary>
        /// 连接集合字符串
        /// </summary>
        /// <param name="collection">字符串集合</param>
        /// <param name="separator">连接字符</param>
        /// <returns></returns>
        public static string JoinString(this IEnumerable<string> collection, string separator) 
        {
            return string.Join(separator, collection);
        }
    }
}
